Wednesday, November 28, 2018

Retirement Planning and Financial Safety

I gave a presentation recently about saving and Financial Safety.
Here's a link to the slides: prezi.com/p/drbqcvfppehl. Use your right-arrow key to progress through the topics.
Let me know if you have any suggestions.

Wednesday, November 21, 2018

Logitech Mouse Buttons Not Working In Visual Studio 2017 or 2019

I love my Logitech Dark Field Performance MX mouse, but in Windows 10 using Visual Studio 2017 or 2019, the buttons won't work.  (Make a sad face with me).

The problem is that the logitech program needs to run with Admin privilege.
To fix:
0. In the System Tray, right click on the "SetPoint" icon and select "exit"
1. In a file browser open "C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Logitech\Mouse and Keyboard"
2. Right click on "Mouse and Keyboard Settings" and select "Properties"
3. Select the "Compatibility" tab.
4. In the "Privilege Level" (or may be named "Settings") panel, select "Run the program as an Administrator".
5. Select "OK"
6. Restart "Mouse and Keyboard Settings" via the start menu.
7. Enjoy the buttons on your mouse in Visual Studio 2017/2019.


Wednesday, October 10, 2018

Agile Austin - Can Selflessness Lead to Collaboration?

This month's Agile Austin featured Erin Randall from Schwab talking on "How Building a Foundation of Selflessness Can Make You -- and Your Company Successful."

Here's my notes:

30% of collaboration in a company comes from 3-5% of the people.

Psychological Safety
  - Team members need to feel accepted and respected
  - They need the shared belief that the team is safe for interpersonal risk taking

Use words carefully

Victim Consciousness/Whole Body Yes:   "I have to ..." / "I get to ..."

"Be kind and full of love... but have boundaries ..."

Chunk your work to see its impact - do things for an extended period of time, not just a few minutes, to feel the impact.

Make certain to do things that fill you up.

Collin Powell said when the troops stop bringing you problems it's because they think you don't care or they think you can't help.

Erin is a big fan of storycubes.com

Give generously.
Acknowledge help.




Monday, August 27, 2018

Adobe Experience Manager (AEM) Examples and Notes

Personal AEM Notes

I just recently started a project at work using Adobe Experience Manager (AEM). Here's my random, rambling collection of notes. If you know of a better way to do any of these examples please let me know by adding a comment.

Good resources:
  1. Jeff's Youtube series Programmer Vs World AEM Series
  2. HTL guide: https://github.com/Adobe-Marketing-Cloud/htl-spec/blob/master/SPECIFICATION.md#225-test
  3. https://github.com/pankajchhatri/AEM

General Tips for Working with AEM

  1. Save often when creating objects - all the time. Create an object, then "Save All", or Ctl-S. All the time. Delete something? Save immediately.
  2. Remember to always to a hard reload of a browser after changing AEM content, Ctl-Shift-R.
  3. Coming from Visual Studio, I found the IntelliJ "Live Edit" plugin and the Chrome plugin very useful.

Jeff's overview of AEM components:

Apache Felix - osgi framework - forces modular sw development - service orentation
Jackrabbit - JCR content repo, JSR-170,283, workspaces, nodes, properties
Sling - Restful Web Framework
Sencha EXT JS 4 - js application framework
Lucene - search engine
Quartz Scheduler - cron system programmatically accessable
CRX - Tar Journal, Package Manager, deploy and share, Servlet Engine CQSE
CRXDE Lite - ide
WCM (Web Content Manager) - this is what content writers use

Folder Structure

/apps: custom templates, components,
/content: stores all content
/etc: client library, design dialog info
/libs: standard components - do not modify
   example:  /libs/wcm/foundation/components/page/
/conf: All configuration
/var: locks,
/home: info about users and groups
/oak:index: Jackrabbit Oak index definitions

Wierd Strings to Put in the URL

Strings to put after "http://localhost:4502" to do wonderful things:


/cf#/ - sets the old interface, e.g., http://localhost:4502/cf#/content/...
/editor.html/ - uses the new interface, e.g., http://localhost:4502/editor.html/content/...
/crx/de - goes straight to the CRXDE page e.g., http://localhost:4502/crx/de
/welcome - go to the Websites/DAM page e.g., http://localhost:4502/libs/cq/core/content/welcome.html
/siteadmin - go to the Websites e.g., http://localhost:4502/siteadmin
/system/console/bundles - shows versions and the console - e.g., http://localhost:4502/system/console/bundles

How to limit use of a template?

    allowed paths: /content(/.*)? /* anywhere under content */
    allowed paths: /content/sports/baseball  /* only under baseball */

How to get rid of <p>&nbsp;</p>?

Make sure the text you entered into the "text" element does not contain an extra carriage return.

How to only iterate a fixed number of times?

<ul data-sly-list="${thelist}">
    <li data-sly-test="${itemList.index < 4}">${itemList}</li>
</ul>

Set default values with the 'or' operator

  ${properties.pageTitle || properties.jcr:title || resource.name}

How to find what version of AEM you're running

http://localhost:4502/system/console/status-productinfo

To skip the AEM link check

add this class

<a x-cq-linkchecker="skip" href="..." />

Chrome screen creeping up?

In Chrome do you ever get CRX/DE screen creeping up the bottom left panel til it takes over the whole screen? The best solution I've found is to right-click and select "inspect" and make sure the Chrome browser is not in full screen mode.

How to get a list of tags and iterate over them

var categories = [];
var tags = resolver.getResource("/etc/tags/mysection").getChildren();
for (var i=1;i<tags.length;i++) {
   categories.push(tags[i].name);//do something
}

What is a "Client Library"?

It organizes resources that we send to the browser (client side) - things like css and JavaScript.

How to include a resource in a page

<div data-sly-resource="${ 'myname' @ resourceType='wcm/foundation/components/parsys'}"></div>

To show a page title

${properties.jcr:title}

How to include other files

<sly data-sly-include="header.html"></sly>

How to iterate over properties

 <ul data-sly-list.child="${currentPage.getProperties}">
    <li>${child}</li>
 </ul>

 or
 
<ul data-sly-repeat.child="${currentPage.getParent.getProperties}">
    <li>${child}</li>
</ul>

How to place a page property on the HTML page

Here's an example of reading a property from the page dialog in JavaScript and putting the value on the page.

<div data-sly-use.bannerTitle="getBannerTitle.js">
    ${bannerTitle}
</div>
getBannerTitle.js
"use strict";
use(function () {
    return  resourcePage.getProperties().get("bannerTitle");
});

To See the Actual jcr Nodes

/content/....

To show an array as text with a seperator

${['apple', 'pear', 'papaya'] @ join=' - '}
generates
apple - pear - papaya

How to format strings

${'person {0} of {1}' @ format=[7,9]}

How to encode a string for a URL

This will replace non-URL friendly characters like ' ' with '%20'.

  ${properties.jcr:title @ context='uri'}
  or
  ${'This is a test' @ context='uri'}
url:This%20is%20a%20test

How to encode a string for simple html content

This will replace non-URL friendly characters like ' ' with '%20'.

${'Texas A & M University' @ context='text'}
generates
&lt;x&gt;Texas A &amp; M University&lt;/x&gt;  

How to put in an AEM HTL comment

<!--/* This is an example comment that will not appear in the browser. */-->

How to use Sly Element so no "div" element is sent to the browser

Use the "sly" element when you don't want to have the extra "div" element

  <div data-sly-include="head.html"></div>
  /* this produces: <div>myhead.html</div> */
  use only the "sly" tag and the surrounding divs are not created.
  <sly data-sly-include="head.html"></sly>
  /* this produces: myhead.html */

How to replace content of HTML Element

  <div data-sly-text="${currentPage.title}">This will not be seen</div>

Simple Example of "use" to Call Server-side JavaScript and Pass Parameters

For example, suppose we need a social icon component, "sharethis", which will accept two variables, url encode them, and return an object with two url-encoded variables. The returned object is named "site". ( I have since learned the right way to do this is with the "context='uri'"):

  ${'This is a test' @ context='uri'} //url:This%20is%20a%20test

In sharethis.html:

<div class="iconContainer" data-sly-use.site="${'sharethis.js' @ title=currentPage.title, url=request.requestURL.toString}">
    <p class="shareThisTitle">Share this:</p>
    <a href="https://www.facebook.com/sharer/sharer.php?href=${site.url}&title=${site.title}" alt="share on facebook" target="_blank" class="nodecoration">
        <img src="/content/dam/design/facebook.png" title="share on facebook" alt="share on facebook" />
    </a>
...
</div>

The variables passed in are accessed by prefacing them with "this.". In the file sharethis.js:

"use strict";
use(function () {
    return {
        title: encodeURIComponent(this.title),
        url: encodeURIComponent(this.url)
       }
});

To Have AEM Automatically Bundle Css And Javascript Files

clientlib
create node / cq:clientlibraryfolder

create clientlib named zurbfoundation
create property 'categories' string[], zurb.foundation
create property 'dependencies' "+" cq.jquery

js.txt
#base=style   //subdirectory name

css.txt
#base=source

<html data-sly-use.clientlib='/libs/granite/slightly/templates/clientlib.html'>

<sly data-sly-call="${clientlib.css @ categories='zurb.foundation'}" />
<sly data-sly-call="${clientlib.js @ categories='zurb.foundation'}" />
or to do both:
<sly data-sly-call="${clientlib.all @ categories='zurb.foundation'}" />

How to do a REST call to get json objects in server-side JavaScript within a proxy

"use strict";
function geturlcontents(url) {
    //put the following values in a config file 
    var proxyHost = "proxy.district13.gov",
    proxyPort = 80,
    username = "katniss",
    password = "ilovearchery";

    var method = new org.apache.commons.httpclient.methods.GetMethod(url),
    client = new org.apache.commons.httpclient.HttpClient(),
    status = new org.apache.commons.httpclient.HttpStatus(),
    inputStream;

    var hostConfiguration = new org.apache.commons.httpclient.HostConfiguration();
    hostConfiguration.setProxy(proxyHost,proxyPort);
    client.setHostConfiguration(hostConfiguration);

    var credentials = new org.apache.commons.httpclient.UsernamePasswordCredentials(username, password);
    var authScope =   new org.apache.commons.httpclient.auth.AuthScope(proxyHost, proxyPort);
    client.getState().setProxyCredentials(authScope, credentials);

    try {
 var statusCode = client.executeMethod(method);
 if (statusCode == status.SC_OK) {
  inputStream = method.getResponseBodyAsString();
 } else {
  console.log(':::Failed to execute http method. status code = '+statusCode + ' for url '+ url);
 }
    } catch (e) {
       console.log(":::exception: "+e);
    } finally {
       method.releaseConnection();
    }
return inputStream;
};

use(function() {
  var inputStream = geturlcontents(this.api);
  return JSON.parse(inputStream).slice(0, this.maxitems);
});

How to do a REST call to get json objects in server-side in JSP within a proxy


<%@include file="/libs/foundation/global.jsp"%>
<%@page import="org.apache.commons.httpclient.*,
org.apache.commons.httpclient.methods.*,
org.apache.commons.httpclient.params.HttpMethodParams,
org.apache.commons.httpclient.auth.*,
org.slf4j.Logger,
org.slf4j.LoggerFactory,
org.apache.sling.commons.json.*,
java.util.Date,
java.io.*"%>

<%
String proxyHost = "myproxy.mycompany.com";
int proxyPort = 80;
String username = "steven";
String password = "spielburg";
String url = "http://www.omdbapi.com/?t=alien&plot=full";

HttpClient client = new HttpClient();
GetMethod method = new GetMethod(url);
HttpStatus status = new HttpStatus();
HostConfiguration hostConfiguration = new HostConfiguration();

hostConfiguration.setProxy(proxyHost, proxyPort);
client.setHostConfiguration(hostConfiguration);
UsernamePasswordCredentials credentials = new org.apache.commons.httpclient.UsernamePasswordCredentials(username, password);
AuthScope authScope = new AuthScope(proxyHost, proxyPort);
client.getState().setProxyCredentials(authScope, credentials);

String jsonString = "[]";
try {
int statusCode = client.executeMethod(method);
application.log(" *** statusCode : " +statusCode);

if (statusCode != HttpStatus.SC_OK) {
       application.log(" *** Method failed: " + method.getStatusLine());
       throw new Exception(" *** client.executeMethod failed for url "+ url + " with http error code " + statusCode);
}
      // Read the response body.
      byte[] responseBody = method.getResponseBody();
      jsonString = new String(responseBody);
 } catch (HttpException e) {
      application.log(" *** Fatal protocol violation: " + e.getMessage());
      e.printStackTrace();
    } catch (IOException e) {
      application.log(" *** Fatal transport error: " + e.getMessage());
      e.printStackTrace();
    } catch (Exception e) {
      application.log(" *** Fatal error: " + e.getMessage());
      e.printStackTrace();
    } finally {
      method.releaseConnection();
    }  

 JSONArray jsonArray = new JSONArray(jsonString);

String countofmoviesString = (String)properties.get("countofmovies");
int countofmovies = Integer.parseInt(countofmoviesString);

%>
<div class="movieTileContainer">
     <ul class="movieTileList" >
<%
int maxMovies = jsonArray.length() > countofmovies ? countofmovies : jsonArray.length();
for(int i=0;i<maxMovies;i++) {
   JSONObject jsonObject = jsonArray.getJSONObject(i);
    String title = (String)jsonObject.get("title");
    String jurl = (String)jsonObject.get("url");
    JSONObject image = (JSONObject) jsonObject.get("movieEntryImage");
    String thumbnailLocation = (String)image.get("thumbnailLocation");
    JSONArray prices = (JSONArray) jsonObject.get("price");

    String price = (String)prices.getJSONObject(0).get("price");

   %>
            <li class="movieTileListItem">
                <div class="content">
                    <div class="movieTileBox">
                        <a class="movieTileLink" title="<%= title %> " href="https://www.MyMovieSite.com<%= jurl %>">
                            <p class="movieTileTitle"><%= title %> </p>
                            <img class="movieTileImage" width="185" height="101" src="https://www.MyMovieSite.com<%= thumbnailLocation %>"
                                 alt="<%= title %>">
                                     <p class="movieTilePrice" <%= price %>
                            </p>
                        </a>
                    </div>
                </div>
            </li>
<% } %>
    </ul>
</div>

Common Resource Types:

text field: granite/ui/components/coral/foundation/form/textfield

number: /libs/granite/ui/components/foundation/form/numberfield

DAM file: granite/ui/components/foundation/form/pathbrowser

How to lowercase a variable

More generally, how to invoke a JavaScript method on an htl variable. Call the method without parenthesis.

<a href="${myvariable.toLowerCase}/mypage.html">

Important AEM directories

/libs/granite/ui/components/foundation - new components
/libs/wcm/foundation/components/

To Add An Editable Area

<div data-sly-resource="${ 'content' @ resourceType='wcm/foundation/components/parsys'}"></div>

To Show AEM Quickstart Frame

add this immediately after body tag and it will present the AEM quickstart frame

<div data-sly-call="/libs/wcm/core/components/init/init.jsp"></div>

How to Create an Editable Button

/components/materialize-button/dialog/items/items/tab1/items
fieldDescription / What do you want the button to say
fieldLabel / Button Text
jscr:primaryType cq:Widget
name / ./buttontext
xtype / textfield
<a>${properties.buttontext}</a>

Unorganized Snippets of Forgotten Thoughts

on components, "group" is category.
to add dialog: rt-click/create...dialog
on tab1, create a node with name of "items" and type of cq:WidgetCollection
  inside items create another node named "buttontext" of type cq:Widget
  in Properties add "xtype/String/textfield"
                add "fieldDescription/String/What do you want the button to say"
  add "fieldLabel/String/Button Text"
  add "name/String/./buttontext"  --name is where it puts the value

from component:
${properties.buttontext}
mainpage.tidy.4.json

(to get a list of entities, API Documentation/CQ/Ext/form)

Monday, July 30, 2018

Problem Solved: Failed to execute goal com.day.jcr.vault:content-package-maven-plugin:0.0.24

While running Maven to build our AEM project at work I kept getting "[ERROR] Failed to execute goal com.day.jcr.vault:content-package-maven-plugin:0.0.24:install (install-package-author) on project myproj_apps: Error while installing package. Check log for details. [Help 1]"

I further tracked it down to this 504 error:

[INFO] Installing myproj_apps (C:\Git\myproj\apps\target\myproj_apps-8.04.1.00-SNAPSHOT.jar) to http://localhost:4502/crx/packmgr/service.jsp
[ERROR] Request to http://localhost:4502/crx/packmgr/service.jsp failed, response=Gateway Timeout

But why would the install timeout on my own box?  If I put "http://localhost:4502/crx/packmgr/service.jsp" into my browser, it replied instantly with a banner message.

I suspected the proxy settings, and sure enough if I add "<useProxy>false</useProxy>" to my execution configuration in the POM it worked!

But where was it trying to use the proxy?  Not in my ~/.m2/settings.xml file.

The culprit turned out to be in my maven install directory's settings.xml file, c:/Program Files/Apache/maven/apache-maven-3.5.3/conf/settings.xml. It had two proxies defined.  The default for "useProxy" is "true", so while trying to install on my local box, maven was trying to use a proxy, which was failing.

Solution:  add "<useProxy>false</useProxy>" to your POM file, or remove the proxy from the maven install directory.

Friday, May 25, 2018

How to Set a Considerate Team "Out-of-Office Event" in Outlook

How to Set a Considerate Team "Out-of-Office Event" in Outlook

Follow these simple rules and your fellow co-worker won't hate you (well they may hate you for other reasons, but not for bad "Out-of-Office" appointments).

Nothing annoys people more than getting an "Out-of-Office Event" in Outlook that marks their time as busy, and then posts them a reminder for the event.

1. Start the "Subject" with your name.  Otherwise people get reminded of appointments labeled, "Dr. Appt" at for a brief moment of panic think it's their "Dr. Appt".  Use a title like "Mitch - OOO" with an optional explanation.
2. Set "Show As" to "Free" so you don't block other calendars.
3. Set "Reminder" to  "None" so people don't get reminder emails
4. Add invited people
5. Under "Response Options" uncheck "Request Responses" (which will also uncheck "Allow New Time Proposals").
6. Send invite
5. Make a separate personal appt with no invitees with the "Show As" to "Out of Office" so coworkers will see you are out-of-office.
6. Set your  Outlook "Out of Office" Automatic message.


Now, take the above text and copy/paste it into a local file on your machine that you promise to review before sending your next "Out-of-Office"message in Outlook.

Wednesday, March 14, 2018

Setting Up a New Windows 10 Machine

Here's my list of things to do with a new windows 10 box in 2018.
(I put it here so I can find it next time I get a new machine.  
Let me know your list of "got to have programs" in the comments.)
 
Set Preferences
-----------
Add environmental variable "HOME" and set to "C:\home\mfincher" so Emacs can find me 
(In the File Explorer, right-click on "This PC", select "properties"/"Advanced system settings"/"Environment Variables...")
Add C:\home\mfincher\bin to environmental variable "Path"
Go into "File Explorer Options" and set "Hidden files and folders"/"Show hidden files..."
  "Display the full path in the title bar"
  and unset "Hide extensions for known file types"
Install Utility Programs
------------------------
Install Chrome and Firefox
Install Emacs
Install spell (https://www.emacswiki.org/emacs/AspellWindows) to C:\opt\Aspell and set emacs to reference that dir
Install Git https://git-scm.com/downloads
   git config --global user.name "Johnny Cash"
   git config --global user.email johnny.cash@gm.com
   git config --global http.proxy http://username:password@proxy.example.org:80/
   git config --global https.proxy http://username:password@proxy.example.org:80/

Install cmder from http://cmder.net/ into C:\opt\Cmdr
   Copy user-aliases.cmd to C:\opt\Cmdr\config
Install Mouse drivers  http://support.logitech.com/en_us/downloads
Install Notepad++ from https://notepad-plus-plus.org
Install Node  https://nodejs.org/en/download/
  npm config set proxy http://username:password@proxy.example.org:80/
  npm config set https-proxy http://username:password@proxy.example.org:80/
Install bower and gulp
  npm install -g bower gulp
Install Maven https://maven.apache.org/download.cgi
Install Paint.Net http://www.getpaint.net/download.html
Install 7-zip for zip/tar files from /http://www.7-zip.org/download.html
Install Visual Studio https://www.visualstudio.com/downloads/
Install ReSharper https://www.jetbrains.com/resharper/download/
Install IntelliJ https://www.jetbrains.com/idea/downloa
Install SourceTree for git repos - https://www.atlassian.com/software/sourcetree 





Install AutoHotKey from https://autohotkey.com/download/
Install Putty.exe and MTPuTTY
Install FileZilla - https://filezilla-project.org/download.php?type=client
Install winscp - http://winscp.net
Install cf - https://cli.run.pivotal.io/stable?release=windows64&source=pws
Install PostMan inside Chrome


Install Microsoft Programs
------------------------
Install SQL Server and Red Gate's SQL Search
Install "Remote Desktop Connection Manager" from https://www.microsoft.com/en-us/download/details.aspx?id=44989 
 
Copy Files From Old Computer
----------------------------
Copy My Documents, My Pictu res, c:\home, c:\opt
copy over all the old databases
Copy over inetpub directories
Copy over old Microsoft Mail archives, *.pst files
Copy root directory of Git files, C:\Git
 

Git Clone Error Solved: "Permission denied (publickey)".

While cloning a repo from BitBucket on my new Windows 10 machine  I ran into this error:

"Permission denied (publickey)."

The problem was that BitBucket didn't know about my new public key.
To add the key, select "Manage Account" from the BitBucket web site,



Select "SSH keys" and then "add". 
Copy your public key from "C:\Users\Me\.ssh\id_rsa.pub" and paste it into the text box.
You should be good to go.

If you haven't already created a public/private key set enter,

ssh-keygen -t rsa -C "your.email@myemailhost.com".


Wednesday, January 24, 2018

How to Add TFS Stories Programmatically Through a URL

You can add TFS stories and features through a browser's URL.  This complements the Template process and is simpler than the real API which should be used for real work.

Here's an example URL to create a task, assign it to person, and enter a description:


https://tfs.example.com/tfs/TopLevel/MediumLevel/Project/_workItems/create/Task?%5BSystem.AssignedTo%5D=Wiley+Coyote&%5BSystem.Description%5D=%3Cp%3EExample+Description+Text.%3C%2Fp%3E

This looks like garbage because it is html encoded.  Plain text, courtesy of www.utilities-online.info/urlencode/  would be:

https://tfs.example.com/tfs/TopLevel/MediumLevel/Project/_workItems/create/Task?[System.AssignedTo]=Wiley+Coyote&[System.Description]=Example+Description+Text.

obkb.com has a quick hex code guide.

This will create a task, but not save it.

Here is a non-trivial example, unescaped, and put on multiple lines for clarity:

https://tfs.example.com/tfs/TopLevel/MediumLevel/Project/_workItems/create/User Story?[System.AssignedTo]=Wiley+Coyote
&[Acme.ENABLE.TRAP.ID]=797
&[Acme.ENABLE.PROJ.ID]=777
&[Microsoft.VSTS.Common.ValueArea]=Business
&[Microsoft.VSTS.Common.AcceptanceCriteria]=The Roadrunner is captured.
&[System.Tags]=Food
&[System.AreaPath]=Plans\Trap
&[System.Title]=Giant Mouse Trap to Catch Roadrunner
&[System.Description]=Order giant mouse trap
Place bird seed in trap
wait for roadrunner to get caught

The tricky part is finding the names of the element you want to add.  Fortunately, you can get a Visual Studio plugin which will allow you to see the standard element names and your companies custom names.

You can download the TFS Process Template Editor here.
It will install into VS2017 under the Tools menu.  Select the Process Editor and the "Work Item Field Explorer".


This will display a list of the field names including your custom defined ones:

This method works will for small tasks, but for larger tasks, use the API.

Wednesday, January 10, 2018

Free Online Image to Text Converter

Today I needed to convert a picture of a spreadsheet to an actual spreadsheet.
I used https://www.onlineocr.net/ and it worked great!
They support output in Text, Microsoft Word, and Microsoft Excel.
I selected 'Text' for the OCR, then imported the text into Excel. 
Directly importing an Excel spreadsheet from the web is a little scary,


Proxy Blocking Abot Spider on Windows

I like Abot Web Crawler. It's written in C# and easy to use. Abot will crawl a website so you can get a site map for analysis. Our company's proxy blocks Abot from working. The solution is simple for windows, just set the HTTP_PROXY environmental variable like this,
set HTTP_PROXY=http://proxy_userid:proxy_password@proxy_addr:proxy_port
For example:
set HTTP_PROXY=http://katniss.everdeen:iMissRue@proxy.district9.gov:80
Also also need to set the proxy for HTTPS_PROXY. Then you can run the spider:
cd c:\Git\Abot\abot-master\Abot.Demo\bin\Debug
Abot.Demo.exe https://www.cnn.com > cnn.txt